package com.sanbi.shield.server.config;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.sanbi.shield.server.shield.ShieldInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;

/**
 * MVC配置
 *
 * @author XiaoQingqing
 * @since 2024/06/17
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    /**
     * 系统时区ID
     */
    private static final ZoneId SYSTEM_ZONE_ID = ZoneId.of("Z");

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

//    @Override
//    public void addCorsMappings(CorsRegistry registry) {
//        //添加映射路径
//        registry.addMapping("/**")
//                //是否发送Cookie
//                .allowCredentials(true)
//                //设置放行哪些原始域   SpringBoot2.4.4下低版本使用.allowedOrigins("*")
//                .allowedOriginPatterns("*")
//                //放行哪些请求方式，放行全部
//                .allowedMethods("*")
//                //放行哪些原始请求头部信息
//                .allowedHeaders("*")
//                //暴露哪些原始请求头部信息
//                .exposedHeaders("*");
//    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter<?> converter : converters) {
            //处理http请求，bean正反序列化
            if (converter instanceof MappingJackson2HttpMessageConverter jsonMessageConverter) {
                ObjectMapper objectMapper = jsonMessageConverter.getObjectMapper();
                //自定义时间序列器
                SimpleModule simpleModule = new SimpleModule();
                // 定义序列化
                simpleModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer());
                simpleModule.addSerializer(LocalDate.class, new LocalDateSerializer());
                simpleModule.addSerializer(LocalTime.class, new LocalTimeSerializer());
                // 定义反序列化
                simpleModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer());
                simpleModule.addDeserializer(LocalDate.class, new LocalDateDeserializer());
                simpleModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer());
                objectMapper.registerModule(simpleModule);
                objectMapper.setTimeZone(TimeZone.getTimeZone(SYSTEM_ZONE_ID));
                jsonMessageConverter.setObjectMapper(objectMapper);
                //类型不匹配时不进行解析，避免JsonMappingException异常
                objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
                //禁用时间戳序列
                objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
            }
        }
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        List<String> excludePathPatterns = new ArrayList<>();
        excludePathPatterns.add("/doc.html*");
        excludePathPatterns.add("/webjars/**");
        excludePathPatterns.add("/swagger-resources/**");
        excludePathPatterns.add("/v2/**");
        registry.addInterceptor(new ShieldInterceptor()).addPathPatterns("/**")
                .excludePathPatterns(excludePathPatterns);
    }

    /**
     * 反序列化LocalDateTime
     */
    public static class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
        @Override
        public LocalDateTime deserialize(JsonParser p, DeserializationContext deserializationContext) throws IOException {
            Instant instant = Instant.ofEpochMilli(p.getLongValue());
            return LocalDateTime.ofInstant(instant, SYSTEM_ZONE_ID);
        }
    }

    /**
     * 序列化LocalDateTime为时间戳
     */
    public static class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
        @Override
        public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            Instant instant = value.atZone(SYSTEM_ZONE_ID).toInstant();
            gen.writeNumber(instant.toEpochMilli());
        }
    }

    /**
     * 反序列化LocalDate
     */
    public static class LocalDateDeserializer extends JsonDeserializer<LocalDate> {
        @Override
        public LocalDate deserialize(JsonParser p, DeserializationContext deserializationContext) throws IOException {
            Instant instant = Instant.ofEpochMilli(p.getLongValue());
            LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, SYSTEM_ZONE_ID);
            return localDateTime.toLocalDate();
        }
    }

    /**
     * 序列化LocalDate为时间戳
     */
    public static class LocalDateSerializer extends JsonSerializer<LocalDate> {
        @Override
        public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            Instant instant = value.atStartOfDay().atZone(SYSTEM_ZONE_ID).toInstant();
            gen.writeNumber(instant.toEpochMilli());
        }
    }

    /**
     * 反序列化LocalTime
     */
    public static class LocalTimeDeserializer extends JsonDeserializer<LocalTime> {
        @Override
        public LocalTime deserialize(JsonParser p, DeserializationContext deserializationContext) throws IOException {
            Instant instant = Instant.ofEpochMilli(p.getLongValue());
            return LocalTime.ofInstant(instant, SYSTEM_ZONE_ID);
        }
    }

    /**
     * 序列化LocalTime为时间戳
     */
    public static class LocalTimeSerializer extends JsonSerializer<LocalTime> {
        @Override
        public void serialize(LocalTime value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            int secondOfDay = value.toSecondOfDay();
            gen.writeNumber(secondOfDay * 1000);
        }
    }
}
